package com.seadragon.app.ksr.service.impl;

import java.util.List;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import com.seadragon.app.ksr.dao.CountyDao;
import com.seadragon.app.ksr.dao.PlaceDao;
import com.seadragon.app.ksr.dao.StateDao;
import com.seadragon.app.ksr.dao.ZipDao;
import com.seadragon.app.ksr.extractor.Extractor;
import com.seadragon.app.ksr.model.Address;
import com.seadragon.app.ksr.model.tiger.County;
import com.seadragon.app.ksr.model.tiger.Place;
import com.seadragon.app.ksr.model.tiger.State;
import com.seadragon.app.ksr.model.tiger.Zip;
import com.seadragon.app.ksr.normalizer.Normalizer;
import com.seadragon.app.ksr.service.AddressService;
import com.seadragon.app.ksr.util.CacheManager;

@Service("addressService")
public class AddressServiceImpl implements AddressService {
	private static Logger logger = LoggerFactory.getLogger(AddressServiceImpl.class);
	
	@Autowired
	private Normalizer addressLine1Normalizer;

	@Autowired
	private Extractor streetNumberExtractor;
	
	@Autowired
	private CountyDao countyDao;
	
	@Autowired
	private PlaceDao placeDao;
	
	@Autowired
	private ZipDao zipDao;
	
	@Autowired
	private StateDao stateDao;
	
	@Autowired
	private CacheManager cacheManager;
	
	@Override
	public boolean compare(Address address1, Address address2) {
		boolean result;
		if(address1.isValid()){
			if(address2.isValid()){
				if(address1.getStreetName().toUpperCase().equalsIgnoreCase(address2.getStreetName().toUpperCase())){
					result = true;
				}else{
					result = false;
				}
			}else{
				String streetNumber = streetNumberExtractor.extract(address2.getAddressLine1());
				String route = addressLine1Normalizer.normalize(address2.getAddressLine1().substring(streetNumber.length()).trim());
				if(streetNumber.equalsIgnoreCase(address1.getStreetNumber()) && route.indexOf(address1.getStreetName().toUpperCase()) >= 0){
					result = true;
				}else{
					result = false;
				}
			}
		}else{
			if(address2.isValid()){
				String streetNumber = streetNumberExtractor.extract(address1.getAddressLine1());
				String route = addressLine1Normalizer.normalize(address1.getAddressLine1().substring(streetNumber.length()).trim());
				if(streetNumber.equalsIgnoreCase(address2.getStreetNumber()) && route.indexOf(address2.getStreetName().toUpperCase()) >= 0){
					result = true;
				}else{
					result = false;
				}		
			}else{
				logger.info("This shouldn't happen: 2 addresses, none of them is geocoded");
				String streetNumber1 = streetNumberExtractor.extract(address1.getAddressLine1());
				String route1 = addressLine1Normalizer.normalize(address1.getAddressLine1().substring(streetNumber1.length()).trim());
				String streetNumber2 = streetNumberExtractor.extract(address2.getAddressLine1());
				String route2 = addressLine1Normalizer.normalize(address2.getAddressLine1().substring(streetNumber2.length()).trim());
				if(streetNumber1.equalsIgnoreCase(streetNumber2) && (route1.indexOf(route2) >= 0 || route2.indexOf(route1) >= 0)){
					result = true;
				}else{
					result = false;
				}
			}
		}
		logger.info("First address: " + address1.toString());
		logger.info("Second address: " + address2.toString());
		if(result)
			logger.info("Two addresses are same addresses!");
		else
			logger.info("They are not different addresses!");
		return result;
	}

	@Override
	public List<County> findAdjacentCounties(String countyName, String statefp) {
		List<County> counties = countyDao.findAdjacentCounties(countyName, statefp);
		for(County county : counties){
			county.setState(cacheManager.getStateByStateFp(statefp));
		}
		return counties;
	}

	@Override
	public List<Place> findAdjacentPlaces(String placeName, String statefp) {
		List<Place> places = placeDao.findAdjacentPlaces(placeName, statefp);
		for(Place place : places){
			place.setState(cacheManager.getStateByStateFp(statefp));
		}
		return places;
	}

	@Override
	public List<Zip> findAdjacentZips(String zipCode) {
		return zipDao.findAdjacentZips(zipCode);
	}

	@Override
	public List<State> findAdjacentStates(String stateName) {
		return stateDao.findAdjacentStates(stateName);
	}

}
